// stores/useGenerationStore.ts
import myRequest from '@renderer/utils/request'
import { ElMessage } from 'element-plus'
import { defineStore } from 'pinia'
import { useConfigStore } from '../stores/configStore'
import { useExPrompt } from '../stores/useExPrompt'
import { useModelStore } from './useModelStore'
import { ipcService } from '@renderer/services/ipcService'

interface GenerationParams {
  prompt: string
  negative_prompt: string
  styles: string[]
  enable_hr: false
  denoising_strength: number
  hr_scale: number
  seed: number
  subseed: number
  subseed_strength: number
  seed_resize_from_h: number
  seed_resize_from_w: number
  batch_size: number
  n_iter: number
  steps: number
  cfg_scale: number
  width: number
  height: number
  restore_faces: false
  tiling: false
  do_not_save_samples: false
  do_not_save_grid: false
  sampler_index: string
  scheduler: string
  send_images: true
  save_images: true
  alwayson_scripts: object,
  random_seed: true
}

interface ComfyUIWorkflow {
  prompt: Record<string, any>
  extra_data?: {
    extra_pnginfo?: {
      workflow: any
    }
  }
}

interface Lora {
  lora_name: string,
  lora_image: string | null,
  strength_model: number,
  strength_clip: number,
  lora_config: string,
  lora_label: string,
  tags: string,
}

const DEFAULT_WORKFLOW: ComfyUIWorkflow = {
  prompt: {
  "3": {
    "inputs": {
      "seed": -1,
      "steps": 20,
      "cfg": 7,
      "sampler_name": "euler",
      "scheduler": "normal",
      "denoise": 1,
      "model": [
        "10",
        0
      ],
      "positive": [
        "6",
        0
      ],
      "negative": [
        "7",
        0
      ],
      "latent_image": [
        "5",
        0
      ]
    },
    "class_type": "KSampler",
    "_meta": {
      "title": "K采样器"
    }
  },
  "4": {
    "inputs": {
      "ckpt_name": "pony\\waiNSFWIllustrious_v110.safetensors"
    },
    "class_type": "CheckpointLoaderSimple",
    "_meta": {
      "title": "Checkpoint加载器（简易）"
    }
  },
  "5": {
    "inputs": {
      "width": 1024,
      "height": 1360,
      "batch_size": 1
    },
    "class_type": "EmptyLatentImage",
    "_meta": {
      "title": "空Latent图像"
    }
  },
  "6": {
    "inputs": {
      "text": "",
      "clip": [
        "10",
        1
      ]
    },
    "class_type": "CLIPTextEncode",
    "_meta": {
      "title": "CLIP文本编码"
    }
  },
  "7": {
    "inputs": {
      "text": "",
      "clip": [
        "4",
        1
      ]
    },
    "class_type": "CLIPTextEncode",
    "_meta": {
      "title": "CLIP文本编码"
    }
  },
  "8": {
    "inputs": {
      "samples": [
        "3",
        0
      ],
      "vae": [
        "4",
        2
      ]
    },
    "class_type": "VAEDecode",
    "_meta": {
      "title": "VAE解码"
    }
  },
  "9": {
    "inputs": {
      "filename_prefix": "ComfyUI",
      "images": [
        "8",
        0
      ]
    },
    "class_type": "SaveImage",
    "_meta": {
      "title": "保存图像"
    }
  },
  "10": {
    "inputs": {
      "loras_json": "[]",
      "verbose": true,
      "model": [
        "4",
        0
      ],
      "clip": [
        "4",
        1
      ]
    },
    "class_type": "MarvelousLoraLoader",
    "_meta": {
      "title": "MarvelousLoraLoader"
    }
  }
}
};

const SAMPLER_NAME_MAP: Record<string, string> = {
  'Euler a': 'euler_ancestral',
  'Euler': 'euler',
  'LMS': 'lms',
  'Heun': 'heun',
  'DPM2': 'dpm_2',
  'DPM2 a': 'dpm_2_ancestral',
  'DPM++ 2S a': 'dpmpp_2s_ancestral',
  'DPM++ 2M': 'dpmpp_2m',
  'DPM++ SDE': 'dpmpp_sde',
  'DPM++ 2M SDE': 'dpmpp_2m_sde',
  'DPM fast': 'dpm_fast',
  'DPM adaptive': 'dpm_adaptive',
  'LMS Karras': 'lms_karras',
  'DPM2 Karras': 'dpm_2_karras',
  'DPM2 a Karras': 'dpm_2_ancestral_karras',
  'DPM++ 2S a Karras': 'dpmpp_2s_ancestral_karras',
  'DPM++ 2M Karras': 'dpmpp_2m_karras',
  'DPM++ SDE Karras': 'dpmpp_sde_karras',
  'DPM++ 2M SDE Karras': 'dpmpp_2m_sde_karras',
  'DDIM': 'ddim',
  'PLMS': 'plms',
  'UniPC': 'uni_pc'
};

const SCHEDULER_NAME_MAP: Record<string, string> = {
  'Automatic': 'normal',
  'karras': 'karras',
  'exponential': 'exponential',
  'sgm_uniform': 'sgm_uniform',
  'simple': 'simple',
  'ddim_uniform': 'ddim_uniform',
  'beta': 'beta',
  'linear_quadratic': 'linear_quadratic',
  'kl_optimal': 'kl_optimal',
}


export const useGenerationStore = defineStore('generation', {
  state: () => ({
    params: {
      prompt: "",                       // 正向关键字
      negative_prompt: "",        // 反向关键字
      styles: [
        "Illustrious"
      ],
      enable_hr: false,                  // 是否开启高分辨率修复
      denoising_strength: 0.7,        // 去噪强度
      hr_scale: 2,                    // 高分辨率修复比例
      seed: -1,                         // 随机种子
      subseed: -1,                      // 子级种子
      subseed_strength: 0,              // 子级种子影响力度
      seed_resize_from_h: -1,
      seed_resize_from_w: -1,
      batch_size: 1,                    // 每次生成的张数
      n_iter: 1,                        // 生成批次
      steps: 20,                        // 生成步数
      cfg_scale: 7,                     // 关键词相关性
      width: 1024,                       // 生成图像宽度
      height: 1360,                      // 生成图像高度
      restore_faces: false,             // 面部修复
      tiling: false,                    // 平铺
      do_not_save_samples: false,
      do_not_save_grid: false,
      sampler_index: "Euler a",            // 采样方法
      scheduler: "Automatic",      // 显式设置调度器
      send_images: true,                 // 是否发送图像
      save_images: true,                // 是否在服务端保存生成的图像
      alwayson_scripts: {},               // alwayson配置
      random_seed: true,
    } as GenerationParams,
    images: [] as string[],
    previewImage: '',
    progress: 0,
    isJob: false,
    eta: '0.0s',
    controller: null as AbortController | null,
    info: '',
    preset: '',
    comfyuiModel: '',
    cycleRandomFlag: false,
    cycleRandomFlagV2: false,
    cycleRandomFlagV3: false,
    userWorkflow: null as string | null,
  }),
  getters: {
    getAllEnabledTags(): string {
      const exPromptStore = useExPrompt();
      // 过滤出 use 为 true 的项目，提取 tags 并合并
      return exPromptStore.items
        .filter(item => item.use) // 只保留启用的项目
        .map(item => item.tags)
        .filter(Boolean) // 过滤空标签
        .join(','); // 合并为一个字符串
    },
    combinedPrompt(): string {
      const exPromptStore = useExPrompt();
      const loraTags = exPromptStore.loraList.map(lora => lora.tags).filter(Boolean);
      const enabledItemTags = this.getAllEnabledTags;
      return [
        enabledItemTags,
        exPromptStore.character.tags,
        exPromptStore.random.tags,
        exPromptStore.ai.tags,
        ...loraTags,
        this.params.prompt,
        this.preset
      ].filter(Boolean).join(',')
    },
    translateText(): string {
      const exPromptStore = useExPrompt();
      const enabledItemTags = this.getAllEnabledTags;
      return [
        enabledItemTags,
        exPromptStore.character.tags,
        exPromptStore.random.tags,
      ].filter(Boolean).join(',');
    },
    comfyuiWorkFlowJson(): string {
  const userWorkflow = this.userWorkflow;
  const currentModel = useModelStore().currentModel;
  const exPrompt = useExPrompt();
  const config = useConfigStore().config;

  // 安全解析JSON
  let workflow: ComfyUIWorkflow;
  try {
    workflow = userWorkflow
      ? { prompt: JSON.parse(userWorkflow) }
      : structuredClone(DEFAULT_WORKFLOW);
  } catch (error) {
    workflow = structuredClone(DEFAULT_WORKFLOW);
  }

  // 节点查找函数
  const findNode = (classType: string) => {
    return Object.entries(workflow.prompt).find(
      ([, node]) => node.class_type === classType
    )?.[0];
  };

  // 生成新节点ID
  const generateNextNodeId = (nodes: Record<string, any>) => {
    const ids = Object.keys(nodes)
      .map(id => parseInt(id))
      .filter(id => !isNaN(id));
    const maxId = ids.length > 0 ? Math.max(...ids) : 0;
    return (maxId + 1).toString();
  };

  // 1. 替换模型加载器
  const checkpointNodeId = findNode("CheckpointLoaderSimple");
  if (checkpointNodeId) {
    workflow.prompt[checkpointNodeId].inputs.ckpt_name = currentModel;
  }

  // 2. Lora处理
  const loraArray: Lora[] = JSON.parse(exPrompt.loraListJson || "[]");
  const useNativeLora = config.useNativeLoraLoader ?? true;

  // 定义模型和CLIP输出节点（初始为检查点节点，增加空值保护）
  let modelOutputNode = checkpointNodeId || "2";
  let clipOutputNode = checkpointNodeId || "2";
  // 记录实际创建的LoraLoader节点ID（用于后续验证）
  const createdLoraNodeIds = new Set<string>();

  // 记录需要重定向的节点
  const nodesToRedirect = new Set<string>();

  if (useNativeLora) {
    // 关键修改：先检查并处理MarvelousLoraLoader节点
    let multiLoraNodeInfo: {
      nodeId: string | null;
      modelInput: [string, number] | null;
      clipInput: [string, number] | null;
      dependentNodes: { nodeId: string; inputKey: string; outputIndex: number }[];
    } = {
      nodeId: null,
      modelInput: null,
      clipInput: null,
      dependentNodes: []
    };

    // 步骤1：查找MarvelousLoraLoader节点并记录其连接信息
    Object.entries(workflow.prompt).forEach(([nodeId, node]) => {
      if (node.class_type === "MarvelousLoraLoader") {
        multiLoraNodeInfo.nodeId = nodeId;

        // 记录MarvelousLoraLoader的输入节点（model和clip）- 增加空值保护
        if (node.inputs?.model && Array.isArray(node.inputs.model)) {
          multiLoraNodeInfo.modelInput = [node.inputs.model[0], node.inputs.model[1]];
        }
        if (node.inputs?.clip && Array.isArray(node.inputs.clip)) {
          multiLoraNodeInfo.clipInput = [node.inputs.clip[0], node.inputs.clip[1]];
        }

        // 记录所有依赖MarvelousLoraLoader输出的节点
        Object.entries(workflow.prompt).forEach(([depNodeId, depNode]) => {
          if (depNodeId === nodeId) return; // 跳过自身

          // 检查依赖model输出的节点
          if (depNode.inputs?.model && Array.isArray(depNode.inputs.model)) {
            const [sourceId, outputIndex] = depNode.inputs.model;
            if (sourceId === nodeId) {
              multiLoraNodeInfo.dependentNodes.push({
                nodeId: depNodeId,
                inputKey: "model",
                outputIndex
              });
            }
          }

          // 检查依赖clip输出的节点
          if (depNode.inputs?.clip && Array.isArray(depNode.inputs.clip)) {
            const [sourceId, outputIndex] = depNode.inputs.clip;
            if (sourceId === nodeId) {
              multiLoraNodeInfo.dependentNodes.push({
                nodeId: depNodeId,
                inputKey: "clip",
                outputIndex
              });
            }
          }
        });
      }
    });

    // 步骤2：如果存在MarvelousLoraLoader节点，先移除它
    if (multiLoraNodeInfo.nodeId) {
      delete workflow.prompt[multiLoraNodeInfo.nodeId];

      // 更新模型和CLIP输入节点：使用原MarvelousLoraLoader的输入节点（增加有效性校验）
      if (multiLoraNodeInfo.modelInput && workflow.prompt[multiLoraNodeInfo.modelInput[0]]) {
        modelOutputNode = multiLoraNodeInfo.modelInput[0];
      }
      if (multiLoraNodeInfo.clipInput && workflow.prompt[multiLoraNodeInfo.clipInput[0]]) {
        clipOutputNode = multiLoraNodeInfo.clipInput[0];
      }

      // 将依赖节点添加到重定向列表
      multiLoraNodeInfo.dependentNodes.forEach(dep => {
        nodesToRedirect.add(dep.nodeId);
      });
    }

    let currentModelNode = modelOutputNode;
    let currentClipNode = clipOutputNode;

    // 步骤3：根据loraArray长度决定是否创建LoraLoader链（增加节点创建有效性校验）
    if (loraArray.length > 0 && workflow.prompt[currentModelNode] && workflow.prompt[currentClipNode]) {
      // 创建LoraLoader节点链
      for (const lora of loraArray) {
        const nodeId = generateNextNodeId(workflow.prompt);
        const comfyPath = convertToComfyUIPath(lora.lora_name);

        // 确保LoraLoader节点正确创建
        workflow.prompt[nodeId] = {
          class_type: "LoraLoader",
          inputs: {
            lora_name: comfyPath,
            strength_model: lora.strength_model || 1.0, // 增加默认值防止参数缺失
            strength_clip: lora.strength_clip || 1.0,   // 增加默认值防止参数缺失
            model: [currentModelNode, 0],
            clip: [currentClipNode, 1]
          },
          _meta: { title: `LoraLoader(${lora.lora_name})` } // 增加元数据便于调试
        };

        createdLoraNodeIds.add(nodeId); // 记录已创建的Lora节点
        currentModelNode = nodeId;
        currentClipNode = nodeId;
      }

      // 更新最终输出节点（验证节点存在性）
      if (createdLoraNodeIds.size > 0) {
        modelOutputNode = currentModelNode;
        clipOutputNode = currentClipNode;
      } else {
        // 降级：Lora节点创建失败时使用原始节点
        modelOutputNode = checkpointNodeId || "2";
        clipOutputNode = checkpointNodeId || "2";
      }
    } else {
      // loraArray为空时：确保使用有效节点
      modelOutputNode = workflow.prompt[currentModelNode] ? currentModelNode : (checkpointNodeId || "2");
      clipOutputNode = workflow.prompt[currentClipNode] ? currentClipNode : (checkpointNodeId || "2");
    }

    // 步骤4：查找所有直接连接到基础模型的节点（补充非MultiLora依赖的节点）
    Object.entries(workflow.prompt).forEach(([nodeId, node]) => {
      // 检查模型输入（排除已在MultiLora依赖中的节点）
      if (node.inputs?.model && Array.isArray(node.inputs.model)) {
        const [sourceId] = node.inputs.model;
        if (sourceId === checkpointNodeId && !nodesToRedirect.has(nodeId)) {
          nodesToRedirect.add(nodeId);
        }
      }

      // 检查CLIP输入（排除已在MultiLora依赖中的节点）
      if (node.inputs?.clip && Array.isArray(node.inputs.clip)) {
        const [sourceId] = node.inputs.clip;
        if (sourceId === checkpointNodeId && !nodesToRedirect.has(nodeId)) {
          nodesToRedirect.add(nodeId);
        }
      }
    });

    // 步骤5：从重定向列表中移除LoraLoader节点自身
    Object.entries(workflow.prompt).forEach(([nodeId, node]) => {
      if (node.class_type === "LoraLoader") {
        nodesToRedirect.delete(nodeId);
      }
    });
  } else {
    // 原有MarvelousLoraLoader处理逻辑保持不变（增加有效性校验）
    let multiLoraNodeId = Object.entries(workflow.prompt).find(
      ([, node]) => node.class_type === "MarvelousLoraLoader"
    )?.[0];

    const isNewNode = !multiLoraNodeId;

    if (!multiLoraNodeId) {
      multiLoraNodeId = generateNextNodeId(workflow.prompt);
    }

    // 确保基础模型节点存在才创建MarvelousLoraLoader
    if (checkpointNodeId && workflow.prompt[checkpointNodeId]) {
      workflow.prompt[multiLoraNodeId] = {
        class_type: "MarvelousLoraLoader",
        inputs: {
          loras_json: exPrompt.loraListJson || "[]", // 增加默认值防止空JSON
          verbose: true,
          model: [checkpointNodeId, 0],
          clip: [checkpointNodeId, 1]
        },
        _meta: { title: "MarvelousLoraLoader" }
      };

      // 设置输出节点为MarvelousLoraLoader
      modelOutputNode = multiLoraNodeId;
      clipOutputNode = multiLoraNodeId;
    } else {
      // 降级：基础模型节点不存在时使用默认节点
      modelOutputNode = "2";
      clipOutputNode = "2";
    }

    // 关键修复：总是重定向（增加节点存在性校验）
    Object.entries(workflow.prompt).forEach(([nodeId, node]) => {
      if (nodeId === multiLoraNodeId) return;

      // 检查模型输入
      if (node.inputs?.model && Array.isArray(node.inputs.model)) {
        const [sourceId] = node.inputs.model;
        if (sourceId === checkpointNodeId) {
          nodesToRedirect.add(nodeId);
        }
      }

      // 检查CLIP输入
      if (node.inputs?.clip && Array.isArray(node.inputs.clip)) {
        const [sourceId] = node.inputs.clip;
        if (sourceId === checkpointNodeId) {
          nodesToRedirect.add(nodeId);
        }
      }
    });
  }

  // 核心修复：精确重定向（增加节点存在性校验，避免无效ID引用）
  nodesToRedirect.forEach(nodeId => {
    const node = workflow.prompt[nodeId];
    if (!node) return;

    // 重定向模型输入（验证目标节点存在）
    if (node.inputs?.model && Array.isArray(node.inputs.model)) {
      const [sourceId, outputIndex] = node.inputs.model;
      const targetNodeExists = workflow.prompt[modelOutputNode];

      if ((sourceId === checkpointNodeId ||
          (sourceId && workflow.prompt[sourceId]?.class_type === "MarvelousLoraLoader")) &&
          targetNodeExists) {
        node.inputs.model = [modelOutputNode, outputIndex];
      } else if (!targetNodeExists) {
        // 降级：目标节点不存在时，回退到基础模型节点
        node.inputs.model = [checkpointNodeId || "2", outputIndex];
      }
    }

    // 重定向CLIP输入（验证目标节点存在）
    if (node.inputs?.clip && Array.isArray(node.inputs.clip)) {
      const [sourceId, outputIndex] = node.inputs.clip;
      const targetNodeExists = workflow.prompt[clipOutputNode];

      if ((sourceId === checkpointNodeId ||
          (sourceId && workflow.prompt[sourceId]?.class_type === "MarvelousLoraLoader")) &&
          targetNodeExists) {
        node.inputs.clip = [clipOutputNode, outputIndex];
      } else if (!targetNodeExists) {
        // 降级：目标节点不存在时，回退到基础模型节点
        node.inputs.clip = [checkpointNodeId || "2", outputIndex];
      }
    }
  });

  // 3. 查找文本节点 (保持方向上下文，增加空值保护)
  const kSamplerId = findNode("KSampler") || findNode("KSamplerAdvanced");

  const findTextNodesConnectedToKSampler = () => {
    if (!kSamplerId || !workflow.prompt[kSamplerId]) return { positive: null, negative: null };

    const findTextNodeInDirection = (startId: string, depth = 0): string | null => {
      if (depth > 5 || !workflow.prompt[startId]) return null; // 增加节点存在性校验
      const node = workflow.prompt[startId];

      if (node.class_type === "CLIPTextEncode") return startId;

      // 处理特殊节点类型（增加输入存在性校验）
      const connectionKeys = ['positive', 'negative', 'conditioning', 'text'];
      for (const key of connectionKeys) {
        if (node.inputs?.[key] && Array.isArray(node.inputs[key]) && node.inputs[key].length >= 2) {
          const result = findTextNodeInDirection(node.inputs[key][0], depth + 1);
          if (result) return result;
        }
      }
      return null;
    };

    const kSampler = workflow.prompt[kSamplerId];
    // 验证KSampler的positive/negative输入存在
    const positiveStartId = kSampler.inputs?.positive?.[0];
    const negativeStartId = kSampler.inputs?.negative?.[0];

    return {
      positive: positiveStartId ? findTextNodeInDirection(positiveStartId) : null,
      negative: negativeStartId ? findTextNodeInDirection(negativeStartId) : null
    };
  };

  // 4. 获取并更新文本节点（增加节点存在性校验）
  const { positive: positiveTextNodeId, negative: negativeTextNodeId } = findTextNodesConnectedToKSampler();

  if (positiveTextNodeId && workflow.prompt[positiveTextNodeId]) {
    workflow.prompt[positiveTextNodeId].inputs.text = this.combinedPrompt || ""; // 增加默认值防止空文本
  }

  if (negativeTextNodeId && workflow.prompt[negativeTextNodeId]) {
    workflow.prompt[negativeTextNodeId].inputs.text = this.params.negative_prompt || ""; // 增加默认值防止空文本
  }

  // 5. 更新KSampler参数（增加节点存在性校验）
  if (kSamplerId && workflow.prompt[kSamplerId]) {
    workflow.prompt[kSamplerId].inputs = {
      ...workflow.prompt[kSamplerId].inputs,
      seed: this.params.seed == -1 ? Math.floor(Math.random() * 1000000) : this.params.seed,
      steps: this.params.steps || 20, // 增加默认值防止参数缺失
      cfg: this.params.cfg_scale || 7.0, // 增加默认值防止参数缺失
      sampler_name: SAMPLER_NAME_MAP[this.params.sampler_index] || 'euler_ancestral',
      scheduler: SCHEDULER_NAME_MAP[this.params.scheduler] || 'normal',
      denoise: 1.0, // 明确默认值
      // 确保model/positive/negative输入引用有效节点
      model: workflow.prompt[modelOutputNode] ? [modelOutputNode, 0] : [checkpointNodeId || "2", 0],
      positive: positiveTextNodeId && workflow.prompt[positiveTextNodeId] ? [positiveTextNodeId, 0] : [findNode("CLIPTextEncode") || "6", 0],
      negative: negativeTextNodeId && workflow.prompt[negativeTextNodeId] ? [negativeTextNodeId, 0] : [findNode("CLIPTextEncode") || "7", 0]
    };
  }

  // 高清放大功能（增加节点存在性校验）
  if (this.params.enable_hr) {
    console.log("启用高清放大功能...");
    const mainKSamplerId = kSamplerId;
    if (!mainKSamplerId || !workflow.prompt[mainKSamplerId]) {
      console.warn("无法添加高清放大：未找到主KSampler节点");
      return JSON.stringify(workflow); // 提前返回避免后续错误
    }

    const latentUpscaleId = Object.entries(workflow.prompt).find(
      ([, node]) => node.class_type === "LatentUpscale"
    )?.[0];

    const hiresSamplerId = latentUpscaleId ? Object.entries(workflow.prompt).find(
      ([, node]) =>
        (node.class_type === "KSampler" || node.class_type === "KSamplerAdvanced") &&
        node.inputs?.latent_image?.[0] === latentUpscaleId
    )?.[0] : null;

    if (latentUpscaleId && hiresSamplerId && workflow.prompt[latentUpscaleId] && workflow.prompt[hiresSamplerId]) {
      // 更新现有高清放大节点
      console.log("更新现有高清放大节点...");
      workflow.prompt[latentUpscaleId].inputs.width = (this.params.width || 512) * (this.params.hr_scale || 2);
      workflow.prompt[latentUpscaleId].inputs.height = (this.params.height || 512) * (this.params.hr_scale || 2);
      workflow.prompt[hiresSamplerId].inputs.denoise = this.params.denoising_strength || 0.7;
    } else {
      // 创建新的高清放大节点链
      console.log("创建新的高清放大节点链...");
      const newLatentUpscaleId = generateNextNodeId(workflow.prompt);
      workflow.prompt[newLatentUpscaleId] = {
        class_type: "LatentUpscale",
        inputs: {
          upscale_method: "nearest-exact",
          width: (this.params.width || 512) * (this.params.hr_scale || 2),
          height: (this.params.height || 512) * (this.params.hr_scale || 2),
          crop: "disabled",
          samples: [mainKSamplerId, 0]
        },
        _meta: { title: "LatentUpscale(Hires)" }
      };

      const newHiresSamplerId = generateNextNodeId(workflow.prompt);
      workflow.prompt[newHiresSamplerId] = {
        class_type: "KSampler",
        inputs: {
          seed: this.params.seed == -1 ? Math.floor(Math.random() * 1000000) : this.params.seed,
          steps: Math.floor((this.params.steps || 20) * 0.7),
          cfg: this.params.cfg_scale || 7.0,
          sampler_name: SAMPLER_NAME_MAP[this.params.sampler_index] || 'euler_ancestral',
          scheduler: SCHEDULER_NAME_MAP[this.params.scheduler] || 'normal',
          denoise: this.params.denoising_strength || 0.7,
          model: workflow.prompt[modelOutputNode] ? [modelOutputNode, 0] : [checkpointNodeId || "2", 0],
          positive: positiveTextNodeId && workflow.prompt[positiveTextNodeId] ? [positiveTextNodeId, 0] : [findNode("CLIPTextEncode") || "6", 0],
          negative: negativeTextNodeId && workflow.prompt[negativeTextNodeId] ? [negativeTextNodeId, 0] : [findNode("CLIPTextEncode") || "7", 0],
          latent_image: [newLatentUpscaleId, 0]
        },
        _meta: { title: "KSampler(Hires)" }
      };

      // 重定向原本连接到主KSampler输出的节点（增加节点存在性校验）
      Object.entries(workflow.prompt).forEach(([nodeId, node]) => {
        if (nodeId === newLatentUpscaleId || nodeId === newHiresSamplerId) return;
        if (!node.inputs) return; // 跳过无输入的节点

        Object.entries(node.inputs).forEach(([key, value]) => {
          if (Array.isArray(value) && value[0] === mainKSamplerId && value[1] === 0) {
            workflow.prompt[nodeId].inputs[key] = [newHiresSamplerId, 0];
          }
        });
      });
    }
  }

  // 6. 更新潜在空间节点（增加节点存在性校验）
  const latentNodeId = findNode("EmptyLatentImage");
  if (latentNodeId && workflow.prompt[latentNodeId]) {
    workflow.prompt[latentNodeId].inputs = {
      width: this.params.width || 512, // 增加默认值防止参数缺失
      height: this.params.height || 512, // 增加默认值防止参数缺失
      batch_size: this.params.batch_size || 1 // 增加默认值防止参数缺失
    };
  }

  // 7. 更新VAE解码节点（增加节点存在性校验）
  const vaeDecodeId = findNode("VAEDecode");
  if (vaeDecodeId && workflow.prompt[vaeDecodeId] && checkpointNodeId && workflow.prompt[checkpointNodeId]) {
    if (Array.isArray(workflow.prompt[vaeDecodeId].inputs.vae)) {
      workflow.prompt[vaeDecodeId].inputs.vae = [checkpointNodeId, 2];
    }
  }

  // 8. 更新保存节点（增加节点存在性校验）
  const saveImageId = findNode("SaveImage");
  if (saveImageId && workflow.prompt[saveImageId]) {
    workflow.prompt[saveImageId].inputs.filename_prefix = `ComfyUI_${Date.now()}`;
    // 确保images输入引用有效节点
    if (!workflow.prompt[workflow.prompt[saveImageId].inputs.images?.[0]]) {
      const vaeDecodeNodeId = findNode("VAEDecode") || "8";
      workflow.prompt[saveImageId].inputs.images = [vaeDecodeNodeId, 0];
    }
  }

  // 最终校验：移除所有无效节点引用（兜底逻辑）
  Object.entries(workflow.prompt).forEach(([nodeId, node]) => {
    if (!node.inputs) return;
    Object.entries(node.inputs).forEach(([key, value]) => {
      if (Array.isArray(value) && value.length >= 2 && !workflow.prompt[value[0]]) {
        // 无效节点引用时，降级到基础模型或默认节点
        const fallbackNode = checkpointNodeId || findNode("CheckpointLoaderSimple") || "2";
        workflow.prompt[nodeId].inputs[key] = [fallbackNode, value[1]];
        console.warn(`节点${nodeId}的${key}输入引用无效节点${value[0]}，已降级到${fallbackNode}`);
      }
    });
  });

  return JSON.stringify(workflow);
}
  },
  actions: {
    async generateImages(): Promise<void> {
      const { config } = useConfigStore();
      return config.sdEngine === 'comfyui'
        ? this.generateComfyUIImages()
        : this.generateWebUiImages();
    },

    async generateWebUiImages(): Promise<void> {
      const { config } = useConfigStore()
      this.progress = 0
      this.eta = '0.0s'
      //this.previewImage = ''
      return new Promise((resolve, reject) => {
        try {
          this.controller = new AbortController()
          this.params.prompt = this.params.prompt.replaceAll('@', '')
          const newState = {
            ...this.params,
            prompt: this.combinedPrompt
          }
          // 提交生成请求
          const generateRequest = myRequest({
            url: config.sdwebuiPath + 'v1/txt2img',
            method: 'post',
            data: newState,
            signal: this.controller.signal // 绑定取消信号
          })

          const pollProgress = async () => {
            this.isJob = true
            let isFrist = true
            try {
              while (this.isJob) {
                const res = await myRequest({
                  url: config.sdwebuiPath + 'v1/progress',
                  params: { _t: Date.now() }, // 防止缓存
                  signal: this.controller?.signal
                })

                // 更新进度
                this.progress = Number((res.data.progress * 100).toFixed(1))
                if (isFrist) {
                  isFrist = false
                }
                else {
                  if (!res.data.state.job) {
                    this.progress = 100
                    this.isJob = false
                  }
                }

                this.eta = `${res.data.eta_relative.toFixed(1)}s`

                // 更新预览图（需SD WebUI启用设置）
                if (res.data.current_image) {
                  //this.previewImage = `data:image/png;base64,${res.data.current_image}`
                }

                // 动态轮询间隔（进度越快查询越频繁）
                await new Promise(r => setTimeout(r,
                  this.progress > 80 ? 300 :
                    this.progress > 50 ? 500 : 1000
                ))
              }
            } catch (e) {
              if (e?.name !== 'AbortError') {
                ElMessage.success(JSON.stringify(e))
              }
            }
          }

          // 将结果处理移到单独方法
          const handleResult = () => {
            resolve()
          }

          // 将错误处理移到单独方法
          const handleError = (error) => {
            reject(error)
          }

          Promise.allSettled([generateRequest, pollProgress()])
            .then(results => {
              const [generateResult] = results
              // 处理生成结果
              if (generateResult.status === 'fulfilled') {
                const res = generateResult.value
                if (Array.isArray(res.data.images)) {
                  this.images = res.data.images.map(
                    item => `data:image/png;base64,${item}`
                  )
                  this.previewImage = this.images[0]
                  this.info = JSON.parse(res.data.info).infotexts
                }
              }

              // 错误处理
              if (generateResult.status === 'rejected') {
                ElMessage.success(JSON.stringify(generateResult.reason))
              }
              handleResult()
            })
            .finally(() => {
              this.isJob = false
            })
            .catch(handleError)
        } catch (error) {
          reject(error)
        }
      })
    },

    async generateComfyUIImages(): Promise<void> {
      const { config } = useConfigStore();
      return new Promise(async (resolve, reject) => {
        // 初始化状态
        this.progress = 0;
        this.eta = '0.0s';
        this.controller = new AbortController();

        try {
          this.params.seed = this.params.random_seed ? Math.floor(Math.random() * 1000000) : this.params.seed
          const workflow = this.comfyuiWorkFlowJson;
          // 2. 提交生成请求
          const { data: { prompt_id } } = await myRequest({
            url: config.comfyuiPath + 'prompt',
            method: 'post',
            data: workflow,
            signal: this.controller.signal
          });

          this.isJob = true;

          // 3. WebSocket 连接管理
          const ws = new WebSocket(config.comfyuiWsPath + 'ws');
          let isResolved = false; // 防止重复 resolve/reject

          // WebSocket 事件封装为 Promise
          const wsPromise = new Promise((wsResolve, wsReject) => {
            ws.onopen = () => {
              this.isJob = true;
            };

            ws.onerror = (error) => {
              if (!isResolved) {
                console.error('WebSocket error:', error);
                wsReject(new Error('WebSocket连接失败'));
              }
            };

            ws.onmessage = (event) => {
              const data = JSON.parse(event.data);
              if (data.data?.prompt_id === prompt_id) {
                switch (data.type) {
                  case 'progress':
                    this.progress = Math.floor((data.data.value / data.data.max) * 100);
                    break;
                  case 'executing':
                    if (!data.data.node) {
                      wsResolve(null); // 生成完成信号
                    }
                    break;
                }
              }
            };
          });

          // 4. 轮询结果封装
          const pollPromise = (async () => {
            try {
              while (this.isJob) {
                const { data: historyData } = await myRequest({
                  url: `${config.comfyuiPath}history/${prompt_id}`,
                  signal: this.controller?.signal
                });

                if (historyData?.[prompt_id]?.status?.completed) {
                  // 获取并处理图片数据
                  const imageUrls = this.extractImageUrls(historyData[prompt_id].outputs);
                  const base64Images = await Promise.all(
                    imageUrls.map(async (url) => {
                      const { data } = await myRequest({
                        url,
                        responseType: 'arraybuffer'
                      });
                      return this.arrayBufferToBase64(data);
                    })
                  );
                  this.images = base64Images
                  this.previewImage = this.images[0];
                  return; // 轮询成功退出
                }

                await new Promise(r => setTimeout(r, 1500));
              }
            } catch (error) {
              if (!isResolved) throw error;
            }
          })();

          // 5. 并行等待结果
          await Promise.race([
            wsPromise,
            pollPromise
          ]).then(() => {
            isResolved = true;
            resolve();
          }).catch((error) => {
            if (!isResolved) {
              isResolved = true;
              reject(error);
            }
          }).finally(() => {
            this.isJob = false;
            ws.close();
          });

        } catch (error) {
          reject(error);
          this.params.seed = -1
        }
      });
    },

    async generateComfyUIImagesV2(): Promise<void> {
      const { config } = useConfigStore();
      return new Promise(async (resolve, reject) => {
        // 初始化状态
        this.progress = 0;
        this.eta = '0.0s';
        this.controller = new AbortController();

        try {
          //"filename_prefix": sanitizeFilename(exPromptStore.random.tags),
          const workflow = this.comfyuiWorkFlowJson;
          

          // 2. 提交生成请求
          const { data: { prompt_id } } = await myRequest({
            url: config.comfyuiPath + 'prompt',
            method: 'post',
            data: workflow,
            signal: this.controller.signal
          });

          this.isJob = true;

          // 3. WebSocket 连接管理
          const ws = new WebSocket(config.comfyuiWsPath + 'ws');
          let isResolved = false; // 防止重复 resolve/reject

          // WebSocket 事件封装为 Promise
          const wsPromise = new Promise((wsResolve, wsReject) => {
            ws.onopen = () => {
              this.isJob = true;
            };

            ws.onerror = (error) => {
              if (!isResolved) {
                wsReject(new Error('WebSocket连接失败'));
              }
            };

            ws.onmessage = (event) => {
              const data = JSON.parse(event.data);
              if (data.data?.prompt_id === prompt_id) {
                switch (data.type) {
                  case 'progress':
                    this.progress = Math.floor((data.data.value / data.data.max) * 100);
                    break;
                  case 'executing':
                    if (!data.data.node) {
                      wsResolve(null); // 生成完成信号
                    }
                    break;
                }
              }
            };
          });

          // 4. 轮询结果封装
          const pollPromise = (async () => {
            try {
              while (this.isJob) {
                const { data: historyData } = await myRequest({
                  url: `${config.comfyuiPath}history/${prompt_id}`,
                  signal: this.controller?.signal
                });

                if (historyData?.[prompt_id]?.status?.completed) {
                  // 获取并处理图片数据
                  const imageUrls = this.extractImageUrls(historyData[prompt_id].outputs);
                  const base64Images = await Promise.all(
                    imageUrls.map(async (url) => {
                      const { data } = await myRequest({
                        url,
                        responseType: 'arraybuffer'
                      });
                      return this.arrayBufferToBase64(data);
                    })
                  );
                  this.images = base64Images
                  this.previewImage = this.images[0];
                  return; // 轮询成功退出
                }

                await new Promise(r => setTimeout(r, 1500));
              }
            } catch (error) {
              if (!isResolved) throw error;
            }
          })();

          // 5. 并行等待结果
          await Promise.race([
            wsPromise,
            pollPromise
          ]).then(() => {
            isResolved = true;
            resolve();
          }).catch((error) => {
            if (!isResolved) {
              isResolved = true;
              reject(error);
            }
          }).finally(() => {
            this.isJob = false;
            ws.close();
          });

        } catch (error) {
          reject(error);
        }
      });
    },

    async loadConfig() {
      try {
        // 从后端获取配置
        const globalConfig = await ipcService.getGlobalConfig();

        // 如果没有 params 字段或不是对象，则使用默认值
        if (!globalConfig || typeof globalConfig !== 'object') {
          return; // 保持当前默认配置不变
        }
        // 使用 Object.assign 将后端参数合并到当前参数
        // 这只会复制与 this.params 属性匹配的值
        Object.assign(this.params, globalConfig);
        if(globalConfig.current_model){
          const modelStore = useModelStore();
          modelStore.currentModel = globalConfig.current_model
        }
      } catch (error) {
        console.error('加载配置失败:', error);
        // 可以在这里处理错误或设置默认值
      }
},

    // 保存配置
    async saveConfig() {
      try {
        const modelStore = useModelStore();
        const config = {
            enable_hr: this.params.enable_hr,
            denoising_strength: this.params.denoising_strength,
            hr_scale: this.params.hr_scale,
            batch_size: this.params.batch_size,
            n_iter: this.params.n_iter,
            steps: this.params.steps,
            cfg_scale: this.params.cfg_scale,
            width: this.params.width,
            height: this.params.height,
            sampler_index: this.params.sampler_index,
            scheduler: this.params.scheduler,
            current_model: modelStore.currentModel,
            random_seed: this.params.random_seed,
         }
        await ipcService.saveConfig(config)
        ElMessage.success('保存配置成功')
        return true
      } catch (error) {
        console.error('保存配置失败:', error)
        return false
      }
    },

    extractImageUrls(outputs: Record<string, any>): string[] {
      const urls: string[] = [];
      const { config } = useConfigStore();
      Object.keys(outputs).forEach(nodeId => {
        const node = outputs[nodeId];

        // 检查是否存在 images 数组
        if (node.images && Array.isArray(node.images)) {
          node.images.forEach((img: any) => {
            // 构造合法 URL
            const params = new URLSearchParams({
              filename: img.filename,
              type: img.type || 'output' // 处理 type 字段
            });

            // 处理 subfolder（如果有）
            if (img.subfolder) {
              params.set('subfolder', img.subfolder);
            }

            urls.push(`${config.comfyuiPath}view?${params}`);
          });
        }
      });
      return urls;
    },

    // 辅助方法：ArrayBuffer 转 Base64
    arrayBufferToBase64(buffer: ArrayBuffer): string {
      const bytes = new Uint8Array(buffer);
      let binary = '';
      for (let i = 0; i < bytes.byteLength; i++) {
        binary += String.fromCharCode(bytes[i]);
      }
      return `data:image/png;base64,${window.btoa(binary)}`;
    },

    async cancelGeneration() {
      const { config } = useConfigStore()
      try {
        // 取消前端请求
        this.controller?.abort()
        await myRequest({
          url: config.sdwebuiPath + 'sdapi/v1/interrupt',
          method: 'POST'
        })
        // 根据当前引擎发送中断命令
        /* if (config.currentEngine === 'sdwebui') {
             await myRequest({
             url: config.sdwebuiPath + 'sdapi/v1/interrupt',
             method: 'POST'
           })
         } else if (config.currentEngine === 'comfyui') {
           await myRequest({
             url: config.comfyuiPath + 'interrupt',
             method: 'POST'
           })
         }*/
      } catch (error) {
        console.error('中断失败:', error)
      }
      this.progress = 0
      this.isJob = false
    },
    async handleDownload(url: string) {
      try {
        // 发送下载请求到主进程（不再自行处理数据）
        ipcService.downloadFile({
          source: url,
          defaultName: `image_${Date.now()}.${getFileExtension(url)}`
        })
        // 监听主进程回调
        ipcService.onDownloadProgress((progress) => {
          //console.log(`下载进度: ${progress}%`)
        })

        ipcService.onDownloadComplete((path) => {
          ElMessage.success(`下载完成：${path}`)
        })
        ipcService.onDownloadError(( error) => {
          ElMessage.error(`下载失败：${error}`)
        })
      } catch (error) {
        ElMessage.error(`下载失败：${error.message}`)
      }
    },
    async setPrests(presets: string) {
      this.preset = presets
    },
    async setNegativePrompt(negative_prompt: string) {
      this.params.negative_prompt = negative_prompt;
    }
  }
})
function getFileExtension(url: string) {
  if (url.startsWith('data:')) {
    const mimeType = url.split(';')[0].split(':')[1]
    return mimeType.split('/')[1] || 'dat'
  }
  return url.split('.').pop().split(/[?#]/)[0]
}

function sanitizeFilename(input: string): string {
  return input.replace(/[\\/:*?"<>|]/g, '_'); // 用下划线替换非法字符
}

function convertToComfyUIPath(absolutePath: string): string {
  const config = useConfigStore().config;

  // 确保有loraPath配置
  if (!config.loraPath) {
    ElMessage.warning('未配置Lora路径，将尝试使用文件名');
    return absolutePath.substring(absolutePath.lastIndexOf('\\') + 1);
  }

  // 处理路径格式 - 使用反斜杠
  const normalize = (path: string) => path.replace(/\//g, '\\');

  const normalizedLoraPath = normalize(config.loraPath);
  const normalizedAbsolutePath = normalize(absolutePath);

  // 检查路径是否在loraPath下
  if (normalizedAbsolutePath.startsWith(normalizedLoraPath)) {
    // 提取相对路径部分 - 保留反斜杠
    let relativePath = normalizedAbsolutePath.substring(normalizedLoraPath.length);

    // 移除开头的反斜杠
    if (relativePath.startsWith('\\')) {
      relativePath = relativePath.substring(1);
    }

    return relativePath;
  }

  // 后备方案：尝试从绝对路径中提取文件名
  const fileName = normalizedAbsolutePath.substring(normalizedAbsolutePath.lastIndexOf('\\') + 1);
  return fileName;
}


